// 需求：
// a. 创建游戏的地图
// b. 创建蛇
// c. 创建食物
// d. 处理蛇的移动
// e. 键盘事件控制蛇的方向
// f. 蛇和食物碰撞检测
// g. 记录分数
// h. 添加开始和暂停等控件

// 面向对象：
    // 添加属性
    // 添加方法

// 编码：
// 1. 构造函数
var Snake = function () {
    // 添加属性
    this.mapElement = document.querySelector(".tt-map");
    this.btnStart = document.querySelector(".btn-start");
    this.btnPause = document.querySelector(".btn-pause");
    this.scoreElement = document.querySelector(".score span");
    // 记录行数
    this.row = 20;
    // 记录列数
    this.col = 20;
    // 记录列的间距
    this.space = 30;
    // 记录所有li标签的数组（大数组）
    this.elements = [];
    // 记录代表蛇标签的数组
    this.snakeArray = [];
    // 记录食物的坐标
    this.foodX = 0;
    this.foodY = 0;
    // 记录蛇的移动方向(right,left,top,bottom)
    this.direction = "right";
    // 记录蛇的坐标位置
    this.x = 2;
    this.y = 0;
    // 记录分数
    this.count = 0;
    // 记录定时器函数
    this.timer = null;
    // console.log(this);
}
// 2. 原型对象
// 添加方法
// Snake.prototype.foo1 = function(){ }
// 添加方法 创建地图
Snake.prototype.createMap = function () {
    // 判断行和列的数量以及列间距
    // this.row = this.row > 20 ? 20 : this.row;
    // this.col = this.col > 20 ? 20 : this.col;
    // this.space = this.space > 30 ? 30 : this.space;
    // 外部循环
    for (var i = 0; i < this.row; i++) {
        // 创建ul标签
        var ul = document.createElement("ul");
        // 设置ul标签的高度
        ul.style["height"] = this.space + "px";
        // 创建小数组
        var arr = [];
        // 内循环
        for (var j = 0; j < this.col; j++) {
            // 创建li标签
            var li = document.createElement("li");
            // 设置li标签的尺寸
            li.style["width"] = this.space + "px";
            li.style["height"] = this.space + "px";
            // 用小数组记录当前行的所有li标签
            arr.push(li);
            // 往ul标签添加li标签
            ul.appendChild(li);
        }
        // 把小数组添加到大数组中
        this.elements.push(arr);
        // 往地图容器添加ul标签
        this.mapElement.appendChild(ul);
    }
    // console.log(this.elements);
}
// 添加方法 创建蛇
Snake.prototype.createSnake = function () {
    // 设置第一行的前3个li标签代表蛇
    for (var i = 0; i < 3; i++) {
        // 设置蛇的类名
        this.elements[0][i].className = "snake";
        // 把当前li标签添加到蛇数组中
        this.snakeArray.push(this.elements[0][i]);
    }
    this.elements[this.y][this.x].className = "snake head";
}
// 添加方法 产生指定范围的随机数
Snake.prototype.myRandom = function (min, max) {
    // 指定范围的随机数
    return Math.floor(Math.random() * (max - min) + min);
}
// 添加方法 创建食物
Snake.prototype.createFood = function () {
    // 随机食物坐标
    this.foodX = this.myRandom(0, this.col);
    this.foodY = this.myRandom(0, this.row);

    // 判断食物是否在蛇身体上
    // 第几行第几列
    if (this.elements[this.foodY][this.foodX].className == "snake") {
        // 重新创建食物
        this.createFood();
    } else {
        // 否则 正常创建食物
        this.elements[this.foodY][this.foodX].className = "food";
    }
}
// 添加方法 蛇的移动的逻辑(重点)
Snake.prototype.snakeMove = function () {
    // 根据蛇移动的方向
    // 水平方向
    if (this.direction == "right") {
        this.x += 1;
    }
    if (this.direction == "left") {
        this.x -= 1;
    }
    // 垂直方向
    if (this.direction == "bottom") {
        this.y += 1;
    }
    if (this.direction == "top") {
        this.y -= 1;
    }
    // 判断蛇是否超出活动范围（提示）
    // 水平方向
    if (this.x < 0 || this.x > (this.col - 1)) {
        alert("水平方向超出范围!");
        clearInterval(this.timer);
        return;
    }
    // 垂直方向
    if (this.y < 0 || this.y > (this.row - 1)) {
        alert("垂直方向超出范围!");
        clearInterval(this.timer);
        return;
    }
    // 处理蛇的移动相关逻辑(蛇头和蛇身体接触)
    for(var i = 0 ; i < this.snakeArray.length ; i ++){
        // 设置蛇身体
        this.snakeArray[i].className = "snake";
        // 判断蛇头和身体接触
        if(this.elements[this.y][this.x] == this.snakeArray[i]){
            alert("蛇吃自己了!");
            clearInterval(this.timer);
            return;
        }
    }

    // 判断蛇与食物的碰撞
    if (this.x == this.foodX && this.y == this.foodY) {
        // 碰撞...
        // 设置当前碰撞食物标签为蛇的外观
        this.elements[this.y][this.x].className = "snake head";
        // 把当前这个食物标签添加到蛇数组中
        this.snakeArray.push(this.elements[this.y][this.x]);
        // 记录分数
        this.count += 1;
        // 显示分数
        this.scoreElement.innerText = this.count;
        // 重新创建食物
        this.createFood();
    } else {
        // 没碰撞
        // 设置蛇数组第一个标签移除类名
        this.snakeArray[0].className = "";
        // 把数组第一个标签删除
        this.snakeArray.shift();
        // 把y和x对应的标签设置为蛇外观
        this.elements[this.y][this.x].className = "snake head";
        // 把y和x对应的标签添加到蛇数组中
        this.snakeArray.push(this.elements[this.y][this.x]);
    }
}
// 添加方法 绑定点击事件
Snake.prototype.addClickEvent = function () {
    // 记录函数作用域的this
    var _this = this;
    // 点击开始按钮(开始)
    this.btnStart.onclick = function () {
        // 测试 蛇移动的逻辑
        // _this.snakeMove();
        _this.autoPlay();
    }
    // 点击暂停按钮(暂停)
    this.btnPause.onclick = function () {
        // 停止执行定时器函数
        clearInterval(_this.timer);
    }

}
// 添加方法 绑定键盘事件
Snake.prototype.addKeyEvent = function () {//作用域1
    // 定义变量记录作用域1的this
    var _this = this;
    var delay = null;
    document.onkeydown = function (event) {//作用域2
        // 判断delay是否有值(防抖)
        if(delay){
            return ;
        }
        // 获取键值码
        var keyCode = event.keyCode;
        console.log(keyCode);
        // 根据键值码判断方向 
        // 如果属性direction等于 "right" , 禁止按下向左按键
        if (_this.direction == "right" && keyCode == 37) {
            return;
        }
        if (_this.direction == "left" && keyCode == 39) {
            return;
        }
        if (_this.direction == "bottom" && keyCode == 38) {
            return;
        }
        if (_this.direction == "top" && keyCode == 40) {
            return;
        }
        // 控制流语句 (设置direction)
        switch (keyCode) {
            case 39:
                _this.direction = "right";
                break;
            case 37:
                _this.direction = "left";
                break;
            case 40:
                _this.direction = "bottom";
                break;
            case 38:
                _this.direction = "top";
                break;
        }
        // 执行延迟函数
        delay = setTimeout(function(){
            clearTimeout(delay);
            delay = null;
        },300)
    }
}
// 添加方法 蛇自动运动
Snake.prototype.autoPlay = function(){ // 作用域1
    // 使用定时器函数 先清除定时器函数(防抖)
    if(this.timer) clearInterval(this.timer);
    // 记录this指针变量
    var _this = this;
    // 执行定时器函数
    this.timer = setInterval(function(){// 作用域2
        // 蛇移动
        _this.snakeMove();
    },100)
}
// 添加方法 初始化
Snake.prototype.init = function () {
    // 调用创建地图的方法
    this.createMap();
    // 调用创建蛇的方法
    this.createSnake();
    // 调用创建食物的方法
    this.createFood();
    // 调用绑定点击事件的方法
    this.addClickEvent();
    // 调用绑定键盘事件的方法
    this.addKeyEvent();
}


// 总结:
    // 1. 面向对象是一种指导编码的思想,有利于项目的维护和拓展
    // 2. 涉及DOM编码
    // 3. 事件,谈到事件函数,关注点为 this 指向
    // 4. 注意定时器函数(是一种异步操作)



// 备注:
    // JS 是一种单线程的脚本语言(从上往下执行的过程)
    // console.log(1);
    // console.log(2);
    // console.log(3);
    // 在控制台上:
    // 1
    // 2
    // 3

    // 事件是个行为,如果这个行为没有发生,那么事件作用域的代码,就不会执行
    // console.log(1);
    // document.body.onclick = function(){
    //     console.log(2);
    // }
    // console.log(3);
    // 在控制台上:
    // 1
    // 3

    // 定时器 ,延迟函数是一种回调函数,这种函数需要满足条件才执行代码
    // console.log(1);
    // var d = setTimeout(function(){
    //     console.log(2);
    // },0)
    // console.log(3);
    // 1
    // 3
    // 2